package io.netty.example.study.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.example.study.client.codec.*;
import io.netty.example.study.common.RequestMessage;
import io.netty.example.study.common.ResponseMessage;
import io.netty.example.study.common.order.OrderOperation;
import io.netty.example.study.util.IdUtil;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.util.concurrent.ExecutionException;

/**
 * 增加一个二级编码器，从 Operation -> RequestMessage，结构变为 5 + 0；
 */
public class ClientV1 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(new NioEventLoopGroup());

        /**
         * 有两个二级 Encoder，
         * 第一个：Operation -> RequestMessage，
         * 第二个：RequestMessage -> ByteBuf；
         */
        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                // 需要注意顺序
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new OrderFrameDecoder());
                pipeline.addLast(new OrderFrameEncoder());
                pipeline.addLast(new OrderProtocolEncoder());
                pipeline.addLast(new OrderProtocolDecoder());

                pipeline.addLast(new OperationToRequestMessageEncoder());

                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
            }
        });

        ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8090);
        channelFuture.sync();

        OrderOperation orderOperation = new OrderOperation(1001, "tudou");
        channelFuture.channel().writeAndFlush(orderOperation);

        /**
         * 虽然有 OperationToRequestMessageEncoder，但直接发 RequestMessage 也是可以的，
         * 因为 MessageToMessageEncoder#write 会判断要写的消息的类型和 MessageToMessageEncoder<> 中的泛型是否一致，
         * 如果不一致就不会 encode，代码如下；
         * RequestMessage requestMessage
         *        = new RequestMessage(IdUtil.nextId(), new OrderOperation(1001, "tudou"));
         * channelFuture.channel().writeAndFlush(requestMessage);
         */

        channelFuture.channel().closeFuture().get();
    }

}
